#ifndef __BASIC_SAFESTACK_H__
#define __BASIC_SAFESTACK_H__

#include <mutex>
#include <atomic>

#ifndef NS_START_THREAD_SAFE
#define NS_START_THREAD_SAFE namespace __thread_safe__ {
#endif

#ifndef NS_END
#define NS_END }
#endif

#ifndef NS_USE_THREAD_SAFE
#define NS_USE_THREAD_SAFE using namespace __thread_safe__;
#endif

NS_START_THREAD_SAFE

template <typename T>
class tpl_stack final {
  struct _Node final {
    _Node(T* _d, _Node* _p) : data(_d), pre(_p) {
    }
    _Node() {
    }
    ~_Node() {
      pre = nullptr;
      data = nullptr;
    }
    _Node(const _Node&) = delete;
    _Node* operator=(const _Node&) = delete;
    T* data = nullptr;
    _Node* pre = nullptr;
  };

  std::mutex m_mutex;
  _Node m_root;
  std::atomic_int m_size;
  _Node* m_pHead;

public:
  tpl_stack() : m_size(0), m_pHead(&m_root) {
  }
  ~tpl_stack() {
    Clear();
  }
  void Push(T* d) noexcept {
    std::lock_guard<std::mutex> _locker(m_mutex);
    _Node* _tmp = new _Node(d, m_pHead);
    m_pHead = _tmp;
    ++m_size;
  }

  T* Pop() noexcept {
    std::lock_guard<std::mutex> _locker(m_mutex);
    if (m_size <= 0) {
      return nullptr;
    }
    _Node* _tmp = m_pHead->pre;
    T* data = m_pHead->data;
    delete m_pHead;
    m_pHead = _tmp;
    --m_size;
    return data;
  }
  inline bool IsEmpty() const noexcept {
    return m_size <= 0;
  }
  inline int GetSize() const noexcept {
    return (int)m_size;
  }
  void Clear() noexcept {
    std::lock_guard<std::mutex> _locker(m_mutex);
    while (m_size > 0) {
      _Node* _tmp = m_pHead->pre;
      delete m_pHead;
      m_pHead = _tmp;
      --m_size;
    }
  }
};

/*
         template<typename T>
         class tpl_stack final {
         public:
         tpl_stack():m_size(0) {};
         ~tpl_stack() {
///TODO: clear
};

public:
void Push(T* task) {
m_mutex.lock();
m_tasks.push(task);
++m_size;
m_mutex.unlock();
};

T* Pop() {
m_mutex.lock();
T* _v = nullptr;
if (!m_tasks.empty()) {
_v = m_tasks.top();
m_tasks.pop();
--m_size;
}
m_mutex.unlock();
return _v;
};

void Clear(){
///TODO: no clear() func. for stack instance.
}

inline int32_t GetSize()const {
return (int32_t)m_size;
};

private:
std::stack<T*> m_tasks;
std::mutex m_mutex;
std::atomic_int m_size;
};
*/

NS_END
#endif
